/*
Module Float Arithmetic Computation Unit
opcode:
000:NOP
001:SQRT
010:FADD
011:FSUB
100:FMUL
101:FDIV
110:FMIN
111:FMAX
*/
//Comment on length_mdiv:
//IN CASE THIS IS discrete FPU in ASIC, 
//we use 4x 26*26 MUL to make pipelined 52*52 MUL
//(LL+(HH<<26)+((HL+LH)<<13)), or even spilt in to 16x 13*13 MUL to optimize timing 
//Actually in FPGA, we have 9*9 MUL Blocks, this should rewrite in to 3x3 mul array
//2x2 array FPU is not effecient
//and FMCX is more effecient (Most FPGAs support automatic 18x18 MUL Block)
//IN CASE FMCX64, we shall use 4x 32*32 MUL
//`define USE_PIPELINED_FPU
module generic_FPU
#(parameter length_exp=11,
            length_val=52,
            length_mdiv=52,
            lengti_dio=length_exp+length_val
)
(
    input [lengti_dio:0]op1,
    input [lengti_dio:0]op2,
    input [2:0]opcode,
    input [2:0]rmod_in,
    output [lengti_dio:0]out,
    input clk,
    input rst
);

    wire [length_val+2:0]addstage1_base_larger; 
    wire [length_val+2:0]addstage1_base_smaller;
    wire [length_exp:0]addstage1_exp;
    wire fadd_signo;  
    wire fadd_sub;      
    wire fadd_much_larger;
    wire fmax_abs;
    wire [length_mdiv-1:0]mulstage1_LL;
    wire [length_mdiv-1:0]mulstage1_LH;
    wire [length_mdiv-1:0]mulstage1_HL;
    wire [length_mdiv-1:0]mulstage1_HH;
    wire mulstage1_sign;
    wire [length_exp:0]mulstage1_exp;
    wire [length_val+1:0]div_divee;
    wire [length_val+1:0]div_diver;
    wire [length_val+1:0]sqrter;
    wire fcalc_abort; 
    wire [msb_op:0]fabort_o;
    wire [msb_op:0]fmax_o;
    wire [msb_op:0]fmin_o;
    wire [9:0]fclass_o;
    //FPU CALCULATION STAGE0:COMPONENT SPLIT, DETECT AND PRE-PROCESS
    defparam FPU_STAGE0.length_exp=length_exp;
    defparam FPU_STAGE0.length_val=length_val;
    defparam FPU_STAGE0.length_mdiv=length_mdiv;
    fpu_s0 FPU_STAGE0
    (
        .op1_i(op1),
        .op2_i(op2),
        .subsel(opcode==3'b011),
        .addstage1_base_larger(addstage1_base_larger), 
        .addstage1_base_smaller(addstage1_base_smaller),
        .addstage1_exp(addstage1_exp),
        .fadd_signo(fadd_signo),  
        .fadd_sub(fadd_sub),      
        .fadd_much_larger(fadd_much_larger),
        .fmax_abs(fmax_abs),
        .mulstage1_LL(mulstage1_LL),
        .mulstage1_LH(mulstage1_LH),
        .mulstage1_HL(mulstage1_HL),
        .mulstage1_HH(mulstage1_HH),
        .mulstage1_sign(mulstage1_sign),
        .mulstage1_exp(mulstage1_exp),
        .div_divee(div_divee),
        .div_diver(div_diver),
        .sqrter(sqrter),
        .fcalc_abort(fcalc_abort), 
        .fabort_o(fabort_o),
        .fmax_o(fmax_o),
        .fmin_o(fmin_o),
        .fclass_o(fclass_o)
    );
    //FPU CALCULATION STAGE1
    defparam FPU_STAGE1.length_exp=length_exp;
    defparam FPU_STAGE1.length_val=length_val;
    defparam FPU_STAGE1.length_mdiv=length_mdiv;
    wire [length_val+3:0]fadd_addresult,
    wire [2*length_mdiv-1:0]fmul_mulresult
    fpu_s1 FPU_STAGE1
    (
        .addstage1_base_larger(addstage1_base_larger), 
        .addstage1_base_smaller(addstage1_base_smaller),
        .addstage1_exp(addstage1_exp),
        .fadd_sub(fadd_sub),      
        .mulstage1_LL(mulstage1_LL),
        .mulstage1_LH(mulstage1_LH),
        .mulstage1_HL(mulstage1_HL),
        .mulstage1_HH(mulstage1_HH),

        .fadd_addresult(fadd_addresult),
        .fmul_mulresult(fmul_mulresult)

    );
    defparam FPU_STAGE2.length_exp=length_exp;
    defparam FPU_STAGE2.length_val=length_val;
    defparam FPU_STAGE2.length_mdiv=length_mdiv;
    wire [lengti_dio:0]fadd_fpout;
    wire [lengti_dio:0]fmul_fpout;
    wire [lengti_dio:0]fsqrt_fpout;
    wire [lengti_dio:0]fdiv_fpout;

    fpu_s2 FPU_STAGE2
    (
        .fadd_addresult(fadd_addresult),
        .fmul_mulresult(fmul_mulresult),
        .fadd_sign(fadd_signo),
        .fadd_expin(addstage1_exp),
        .fmul_sign(mulstage1_sign),
        .fmul_expin(mulstage1_exp),
        .rounding_mode(rmod_in),
        .fadd_fpout(fadd_fpout),
        .fmul_fpout(fmul_fpout)
    );

endmodule

